package se.webbzon.boltzmann.game.object.dialogue;

import java.awt.Point;
import java.util.List;

import se.webbzon.boltzmann.game.object.dialogue.DialogueArrow.Direction;
import se.webbzon.boltzmann.game.object.dialogue.layout.ItemDialogueLayout;
import se.webbzon.boltzmann.game.object.dialogue.word.AbstractDialogueWord;
import se.webbzon.boltzmann.game.object.dialogue.word.ImageDialogueWord;
import se.webbzon.boltzmann.game.object.player.AbstractPlayerCharacter;
import se.webbzon.boltzmann.game.sequence.builder.AbstractSequenceBinding;
import se.webbzon.boltzmann.input.Button;
import se.webbzon.boltzmann.input.Input;
import se.webbzon.boltzmann.inventory.Inventory;
import se.webbzon.boltzmann.item.AbstractItem;
import se.webbzon.boltzmann.player.Player;
import se.webbzon.boltzmann.resource.Resources;
import se.webbzon.oschi01.worldarea.WorldArea;
import se.webbzon.oschi01.worldobject.WorldStaticObject;
import se.webbzon.oschi01.worldobject.appearance.GroupAppearance3D;

public class ItemDialogue extends AbstractDialogue {
	
	// The image used for the default item (none)
	private final String defaultTextureSetName = "item_none";
	
	// The image dialogue word associated with this item dialogue
	private final ImageDialogueWord image;
	
	// The items of the dialogue
	private final AbstractDialogueItem leftArrow, rightArrow, circle;
	
	// The position of the item in the inventory
	private final Point itemPosition;
	
	// The player associated with this item dialogue
	private volatile Player player;
	
	// The selected item
	private volatile AbstractItem item;
	
	// Calls all the listeners in the next step if set
	private volatile boolean proceed;

	// Shows all the words in the next step if set
	private volatile boolean showAll;

	/*============================================================
	Constructor
	============================================================*/
	
	/** Creates a new item dialogue with a given layout, background and
	 * text. **/
	public ItemDialogue(ItemDialogueLayout layout, 
						DialogueBackground background,
						String text) {
		this(layout,background,DialogueTextParser.parse(layout, text));
	}
	
	/** Creates a new item dialogue with a given layout, background and
	 * list of words. **/
	public ItemDialogue(ItemDialogueLayout layout, 
						DialogueBackground background,
						List<AbstractDialogueWord> words) {
		super(layout, background, words);
		
		itemPosition = new Point();

		// Create the dialogue image
		image = new ImageDialogueWord(layout,defaultTextureSetName);
		image.setPosition(-image.getWidth()/2, layout.getItemYOffset(), 0);
		image.hide();
		
		final double size = layout.getCharacterWidth();
		final double y = layout.getItemYOffset() - image.getHeight()/2;
		final double x = image.getWidth()/2 + layout.getItemXSpacing();
		
		// Create the left and right arrows
		leftArrow = new DialogueArrow(Direction.LEFT,2);
		leftArrow.setSize(size, size, 1);
		leftArrow.setPosition(-x, y, 0);
		leftArrow.hide();
		
		rightArrow = new DialogueArrow(Direction.RIGHT,2);
		rightArrow.setSize(size, size, 1);
		rightArrow.setPosition(x, y, 0);
		rightArrow.hide();
		
		// Create continue circle
		circle = new DialogueCircle(layout.getCircleRadius());
		circle.setPosition(
				layout.getWidth()/2 - layout.getCircleRadius()*2, 
				layout.getCircleYSpacing(), 
				0);
		circle.hide();
		
		// Add items to dialogue
		GroupAppearance3D appearance = (GroupAppearance3D) getAppearance();
		appearance.addAppearance(image.getAppearance());
		appearance.addAppearance(leftArrow.getAppearance());
		appearance.addAppearance(rightArrow.getAppearance());
		appearance.addAppearance(circle.getAppearance());
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Returns the selected item in this dialogue. **/
	public AbstractItem getItem() {
		return item;
	}
	
	/** Returns the position of the selected item in this dialogue. **/
	public void getItemPosition(Point itemPosition) {
		itemPosition.setLocation(this.itemPosition);
	}
	
	@Override public boolean display(WorldStaticObject talker) {
		if (super.display(talker)) {
			final AbstractPlayerCharacter character;
			character = (AbstractPlayerCharacter)
					getSequence().getBinding(AbstractSequenceBinding.PLAYER);
			player = character.getPlayer();
			item = player.getSelectedItem();
			
			// Select an item from the players inventory
			if (item == null) {
				Inventory inv = player.getInventory();
				if (player.getInventory().getNumberOfItems() == 0)
					image.setTextureSet(defaultTextureSetName);
				
				else {
					outerLoop:
					for (int row = 0; row < inv.getRows(); row++)
						for (int column = 0; column < inv.getColumns(); column++) {
							item = inv.getItem(row, column);
							if (item != null) {
								itemPosition.setLocation(row, column);
								break outerLoop;
							}
						}
					image.setTextureSet(item.getTextureSet());
				}
				
			} else { 
				player.getInventory().getPosition(item, itemPosition);
				image.setTextureSet(item.getTextureSet());
			}
			
			return true;
		} else
			return false;
	}
	
	@Override public void onStep(WorldArea world) {
		super.onStep(world);
		if (proceed) {
			proceed = false;
			notifyOnContinue();
		} else if (showAll) {
			showAll = false;
			showAllWords();
		}
	}

	@Override public void primaryAxisChanged(Input input, double direction, double value) {};

	@Override public void secondaryAxisChanged(Input input, double direction, double value) {};

	@Override public void buttonPressed(Input input, Button button) {
		if (isInputReady()) {
			switch (button) {
			case ACTION:
				if (isAllVisible())
					proceed = true;
				else
					showAll = true;
				break;
			case LEFT:
			case PREVIOUS_ITEM:
				previousItem();
				break;
			case RIGHT:
			case NEXT_ITEM:
				nextItem();
				break;
			}
		}
	}

	@Override public void buttonReleased(Input input, Button button) {};
	
	@Override public void bindingAccepted(Input input, Button button) {};

	@Override public void onShowInput() {
		image.display();
		leftArrow.display();
		rightArrow.display();
		circle.display();
	}

	@Override public void onHideInput() {
		image.hide();
		leftArrow.hide();
		rightArrow.hide();
		circle.hide();
	}
	
	/*============================================================
	Private Methods
	============================================================*/
	
	/** Switches to the next item in this item dialogue. **/
	private void nextItem() {
		Inventory inv = player.getInventory();
		if (inv.getSuccessor(item, itemPosition)) {
			item = inv.getItem(itemPosition.x, itemPosition.y);
			image.setTextureSet(item.getTextureSet());
		}
	}
	
	/** Switches to the previous item in this item dialogue. **/
	private void previousItem() {
		Inventory inv = player.getInventory();
		if (inv.getPredecessor(item, itemPosition)) {
			item = inv.getItem(itemPosition.x, itemPosition.y);
			image.setTextureSet(item.getTextureSet());
		}
	}
	
	/** Notifies all listeners to continue. **/
	private void notifyOnContinue() {
		for (DialogueListener listener : getListeners().toArray(new DialogueListener[0])) {
			if (listener instanceof ItemDialogueListener)
				((ItemDialogueListener) listener).onContinue(this, item);
		}
	}

}
